if(typeof(mstar)=="undefined"){
	var mstar = {};
}
mstar.flotUtil = {
    floorInBase: function(n, base) {
        return base * Math.floor(n / base);
    },
	colorToRGB:function(colorHex,alpha){
		var c = this.colorType(colorHex);
		if(arguments.length>1){
			return "rgba("+c.r+","+c.g+","+c.b+","+alpha+")";
		}else if(c.t=="rgba"){
			return "rgba("+c.r+","+c.g+","+c.b+","+c.a+")";
		}else{
			return "rgb("+c.r+","+c.g+","+c.b+")";
		}
	},
	colorType:function(colorHex){
		var color={t:"rgb",r:255,g:255,b:255,a:1},result="";
        if (result = /#([a-fA-F0-9]{2})([a-fA-F0-9]{2})([a-fA-F0-9]{2})/.exec(colorHex)){
			color={t:"h6",r:parseInt(result[1], 16),g:parseInt(result[2], 16),b:parseInt(result[3], 16),a:1};
		}else if (result = /#([a-fA-F0-9])([a-fA-F0-9])([a-fA-F0-9])/.exec(colorHex)){
			color={t:"h3",r:parseInt(result[1]+result[1], 16),g:parseInt(result[2]+result[2], 16),b:parseInt(result[3]+result[3], 16),a:1};
		}else if (result = /rgb\(\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*\)/.exec(colorHex)){
			color={t:"rgb",r:parseInt(result[1], 10),g:parseInt(result[2], 10),b:parseInt(result[3], 10),a:1};
		}else if (result = /rgba\(\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]+(?:\.[0-9]+)?)\s*\)/.exec(colorHex)){
			color={t:"rgba",r:parseInt(result[1], 10),g:parseInt(result[2], 10),b:parseInt(result[3], 10),a:parseFloat(result[4])};
		}
		return color;
	},
	colorRange:function(c){
		return c<0?0:(c>255?255:c);
	},
	avoidSelect:function(){
		if(!$.browser.msie||$.browser.msie&&parseInt($.browser.version)!=8){
			window.getSelection ? window.getSelection().removeAllRanges() : document.selection.empty();	
		}
	}
};

mstar.flot = function (targetID,_option){
    this.options = {
        // the color theme used for graphs //#2f4880
        colors:["#728fb2", "#9b0033","#e96610","#f1ad02","#9faa00","#006065","#809aba","#e1b2c1",
				"#e2e5b2","#293f6f","#fbe6b3","#f2a370","#b2cfd0", "#bec5d4","#c5cc66","#f8d1b7","#c36685","#c9cbcb","#ff7f27"],//QS_Style.chart.tickerColors,
        xaxis: {
            mode: null, // null or "time"
            min: null, // min. value to show, null means set automatically
            max: null, // max. value to show, null means set automatically
            autoscaleMargin: null, // margin in % to add if auto-setting min/max
            ticks: null, // either [1, 3] or [[1, "a"], 3] or (fn: axis info -> ticks) or app. number of ticks for auto-ticks
            tickFormatter: null, // fn: number -> string
            labelWidth: null, // size of tick labels in pixels
            labelHeight: null,
            showLabel:true, // is show label.
            // mode specific options
            tickDecimals: null, // no. of decimals, null means auto
            tickSize: null, // number or [number, "unit"]
            minTickSize: null, // number or [number, "unit"]
            monthNames: null, // list of names of months
            timeformat: null, // format string to use
            posStyle:null,
			textAlign:"left"
        },
        yaxis: {
            autoscaleMargin: 0.02,
            showLabel:true,
            scaleType:0,
			align:"right",
			labelFormatter:null,
			showLastLabel:false,
			minTopLine:NaN,//add by alex
			minBottomLine:NaN
        },
        x2axis: {
            autoscaleMargin: null,
            showLabel:true
        },
        y2axis: {
            autoscaleMargin: 0.02,
            showLabel:false
        },              
        points: {
            show: false,
            radius: 1.5,
            lineWidth: 2, // in pixels
            fill: false,
            fillColor: "#ffffff"
        },
        lines: {
            show: false,
            lineWidth: 2, // in pixels
            fill: true,      
            fillColor:"#4A596A" ,//"#c9d2dd",
			lineType:"mountain",//"line,mountain,dot,ab",
			dot:{radius:2,fill:true,color:"#728fb2"},
			ab:{showBorder:true,aColor:"#65A125",bColor:"#CA3239",mColor:"#fff",midLineValue:NaN,bHasCloseLine:true}
        },
        bars: {                  
            show: false,
            outLine:false,
            lineWidth: 2, // in pixels
            barWidth: 1, // in units of the x axis
            minBarWidth:2,
            maxBarWidth:16,
            upColor:"#008000",
	        downColor:"#ff0000",
            fill: true,
            fillColor: null,
            align: "left" // or "center"
        },
        OLHC: {
          show: false,
          lineWidth: 2, // in pixels
          fill: false,
          fillColor: null,
          maxBarWidth:10,
          minBarWidth:2,
          barWidth:null,
          highLightColor:"#ff0000",
		  olhcType:"ohlc"//type of ohlc hlc
        },
        candleStick: {
	        show:false,
	        lineWidth:1,
	        fill:true,
	        upColor:"#008000",
	        downColor:"#ff0000",
	        maxCandleWidth:16,
	        minCandleWidth:2,
	        candleWidth:null,
	        highLightColor:"#2f4880"
        },
		volumeByPrice:{
			show:false,
			fillColor:"#999d9c",//#ccc
			highlightColor:"#508a88",
			opacity:0.5
		},
        imagePoints: {
            show: false,
            imageObj:null
        },
        points: {
            show: false,
            radius: 1.5,
            lineWidth: 2, // in pixels
            fill: false,
            fillColor: "#ffffff"
        },
        grid: {
            color:"#545454", // primary color used for outline and labels//545454
            backgroundColor: null, // null for transparent, else color
            tickColor:"#dddddd", // color used for the ticks
            labelMargin: 6, // in pixels
            borderWidth: 0.5,
            markings: null, // array of ranges or fn: axes -> array of ranges
            markingsColor: "#f4f4f4",
            markingsLineWidth: 1,
            // interactive stuff
            clickable: false,
            hoverable: false,
            autoHighlight: true, // _highlight in case mouse is near
            mouseActiveRadius: 10, // how far the mouse can be away to activate an item
            bottomColor:"#666666",
			_borderColor:"#fff"
        },
		showGridLines:true,
        higlightIndex:0,  // when mouse over the chart , _highlight one of the data points in series.
        drawingAble:true,
		imageHighlight:true
    };
	this.text={mini_chart_no_data:"Data not available"};
	this.drawObj = null;
    this.series = [];
    this.canvas = null;        // the canvas for the plot itself
    this.overlay = null;      // canvas for interactive stuff on top of plot
    this.eventHolder = null; // jQuery object that events should be bound to
    this.ctx = null;               
    this.octx = null;
    this.target = typeof(targetID)=="string"?$("#"+targetID):targetID;
    this.axes = { xaxis: {}, yaxis: {}, x2axis: {}, y2axis: {} };
    this.plotOffset = { left: 0, right: 0, top: 0, bottom: 0};
    this.canvasWidth = 0;
    this.canvasHeight = 0;
    this.plotWidth = 0;
    this.plotHeight = 0;
    /* interactive parameters*/
    this.lastMousePos = { pageX: null, pageY: null };
    this.highlights = [];
    this.redrawTimeout = null;
    this.hoverTimeout = null;
	this.volumeByPrice={show:false,series:{},area:[],highlights:[],hintDom:null,data:null,index:0,scale:0.4};
    this.__parseOptions(_option);
    this.__constructCanvas();
	this.imgDataList = [];
	this._dataAvailable = false;
	this.drawObj  = new mstar.draw(null,null,this.target);
}
mstar.flot.prototype = {
	//init,render chart
    init: function(data){              
        this.canvasWidth = this.target.width();
        this.canvasHeight = this.target.height();
        this.clearHighlights();
		this.imgDataList=[];
		
		if(!this._processData(data)){
			this._dataAvailable=false;
			this._removeDrawing();
			return;
		}
		this._removeDrawing();
		this._dataAvailable=true;
        this._calculateAndMeasure();
		this._constructChart();
    },
	renderNote:function(data){
		this.drawObj.renderNote(this.series[0],data,this.target);
	},
	//set chart width and height
	resizeCanvas: function(width,height) {
		this.target.css({width: width+"px",height:height+"px"});
        var bIsIE = $.browser.msie;
        this.canvasWidth = width;
        this.canvasHeight = height;
        this.canvas.width = width;
        this.canvas.height = height; 
        this.overlay.width =  this.canvasWidth;
        this.overlay.height = this.canvasHeight;      
        if (bIsIE&&parseInt($.browser.version)<9) {  // excanvas hack
            this.canvas = window.G_vmlCanvasManager.initElement(this.canvas); 
            this.overlay = window.G_vmlCanvasManager.initElement(this.overlay);
        }
        this.ctx = this.canvas.getContext("2d");
        this.octx = this.overlay.getContext("2d");
        this.eventHolder = $([this.canvas,this.overlay]);
	},
	//change the size of chart
	changeOutSize: function(width,height) {
        this.resizeCanvas(width,height);  
		if(!this._dataAvailable)  {
			return;
		} 
        this._calculateAndMeasure();
        this._constructChart();
		//this.drawObj.changeClosePos(this.axes,this.plotOffset);
		this._triggerRedrawOverlay();
    },
	//set option
	setOption:function(op) {
        if(op.xaxis && op.xaxis.ticks != null) {
            this.options.xaxis.ticks = null;
        }
		if(op.colors && op.colors.length){
			this.options.colors = null;
		}
        $.extend(true, this.options, op);
    },
	//clear the highlights in the overlay canvas
    clearHighlights: function() {
        if (this.highlights != null && this.highlights.length > 0) {  // clean _highlight points
            var h;             
            for (var i = 0; i < this.highlights.length; ++i) {
               h = this.highlights[i];
               if (h.auto) {
                   this._unhighlight(h.series, h.point);
               }
           }
       }
    },
	//for chart drawing(rectangle,ellipse,trendline,note)
	beginDrawing:function(type){
		
		for(var t in this.drawObj.getDrawTypes()){
			this.drawObj.setDrawType(t,false);
			if(type==t){
				this.drawObj.setDrawType(t,true);
			}
		}
		//this.drawObj.setDrawType("levelline",true);
	},
	//active end drawing
	cancelDrawing:function(type){
		for(var t in this.drawObj.getDrawTypes()){
			if(type==t){
				this.drawObj.setDrawType(t,false);
			}
		}
	},
	getDataPostion:function(x,y){
		return [this.axes.xaxis.p2c(x),this.axes.y2axis.p2c(y)];
	},
    __constructCanvas: function() {
        this.target.find("canvas").remove();
        this.target.css({position: "relative","float":"left"}); // for positioning labels and overlay  
        this.canvasWidth = this.target.width();
        this.canvasHeight = this.target.height();
        this._clearTickLabels();
        // for positioning labels and overlay
        if (this.canvasWidth <= 0 || this.canvasHeight <= 0){
        	throw "Invalid dimensions for plot, width = " + this.canvasWidth + ", height = " + this.canvasHeight;
		}
        if(this.canvas == null) {
            this.__createCanvas();
        }
        // bind events
        this.__attachFlotEvent();
    },	
	__createCanvas: function(){
        if(this.ctx == null && this.canvas != null) {
            this._clearCanvas();
        }
        var bIsIE = $.browser.msie;
        if(bIsIE&&parseInt($.browser.version)<9) { 
            window.G_vmlCanvasManager.init_(document); // make sure everything is setup  
        }
        this.canvas = document.createElement("canvas");
        this.canvas.width =  this.canvasWidth;
        this.canvas.height = this.canvasHeight; 
        this.canvas.style["float"] = "left";
        this.target.append(this.canvas); 
        if (bIsIE&&parseInt($.browser.version)<9) { // excanvas 
            this.canvas = window.G_vmlCanvasManager.initElement(this.canvas); 
        }
        this.ctx = this.canvas.getContext("2d");   
        this.overlay = document.createElement("canvas");
        this.overlay.width =  this.canvasWidth;;
        this.overlay.height = this.canvasHeight;
        this.overlay.style.position = "absolute";
        this.overlay.style.left="0px";
        this.overlay.style.top="0px";
        this.target.append(this.overlay); 
        if (bIsIE&&parseInt($.browser.version)<9) {  // excanvas 
            this.overlay = window.G_vmlCanvasManager.initElement(this.overlay);
        }
        this.octx = this.overlay.getContext("2d");
        this.eventHolder = $([this.canvas,this.overlay]);
    },
	__parseOptions: function(o) {
        this.options.xaxis.ticks = null;
        $.extend(true, this.options, o);
        if (this.options.xaxis.noTicks && this.options.xaxis.ticks == null)
            this.options.xaxis.ticks = this.options.xaxis.noTicks;
        if (this.options.yaxis.noTicks && this.options.yaxis.ticks == null)
            this.options.yaxis.ticks = this.options.yaxis.noTicks;
    },
	__attachFlotEvent: function() {
        var self = this;
        if (this.options.grid.hoverable) {
            // FIXME: temp. work-around until jQuery bug 4398 is fixed
            self.eventHolder.each(function () {
		
				$(this).bind("mousemove",function(e){
				
					self._onMouseMove.call(self, e);
				});
                //this.onmousemove = function(e){self._onMouseMove.call(self, e);};
            });
			$(self.eventHolder).bind("mousedown",function(e){
				self._onMouseDown.call(self,e);
			});
            //self.eventHolder.mousedown(function(e){self._onMouseDown.call(self,e);});
        } 
        if (this.options.grid.clickable) {
            self.eventHolder.click(function(e){self._onClick.call(self,e);});
			self.eventHolder.dblclick(function(e){self._ondbClick.call(self,e);});//trend line
        }
    },
	_createLegend:function(value,label,left,top){
		var str = '<div class="changeHintDiv rtq-chart-hover-hint" style="display: block; left: '+left+'px; top: '+top+'px;">';
		str+='<div class="wrap-img"><img border="0" src="theme/black/arrow.gif" class="arrow">';
		str+='<span class="wrap-text-close"><span class="rtq-trendline-hinttext">'+value+'|'+label+'</span>';
		str+='</span></div></div>'; 
		return $(str).appendTo(this.target.find(".tickLabels"));
	},
	_removeDrawing:function(){
		if (!this.volumeByPrice.show&&this.volumeByPrice.hintDom != null) {
                this.volumeByPrice.hintDom.hide();
            }
		if(!this.options.drawingAble){
			this.drawObj.clearDrawing(this.target);
		}else if(this.series[0].data !=undefined){
			this.drawObj.clearDrawing(this.target);
			/*if(this.series[0].data.length !=this.drawObj.drawing.count||typeof(this.series[0].data[0])=="undefined"||(this.series[0].data[0][this.series[0].data[0].length-1]+"_"+this.series[0].data[this.series[0].data.length-1][this.series[0].data[this.series[0].data.length-1].length-1])!=this.drawObj.drawing.startend){
				this.drawObj.clearDrawing(this.target);
			}else{
				this.drawObj.changeClosePos(this.axes,this.plotOffset);
			}*/
		}
		this._triggerRedrawOverlay();
	},
    _clearTickLabels: function() {
        this.target.find(".tickLabels").html("");
    },
    _processData: function(d) {
        this.series = this._parseData(d);
		if(this._checkData(this.series)){return false;}
        this._parseOptionToSeries();
		this._calculateAxisExtreme();
		return true;
    },
	_checkData:function(d){//check data for null or [[],[]]
		var flag = false;
		if(d==null||d.length==0){
			flag = true;
		}else{
			for(var i = 0;i<d.length;i++){
				if(d[i].data.length>0){break;}
				if(i==d.length-1){flag = true;}
			}
		}
		var noData = this.target.find(".flot-minichart");
		if(flag){
			this.ctx.clearRect(0, 0, this.canvasWidth, this.canvasHeight);
			this._clearTickLabels();
			if(noData.length==0){
				var str = "<div class='flot-minichart'>"+this.text.mini_chart_no_data+"</div>";
				this.target.append(str);
			}else{
				noData.show();
			}
		}else{
			noData.hide();
		}
		return flag;
	},
    _parseData: function(d) {
        var res = [];
       	for (var i = 0; i < d.length; ++i) {
            var s;
            if (d[i].data) {
                s = {};
                for (var v in d[i])
                    s[v] = d[i][v];
            }
            else {
                s = {data: d[i] };
            }
            res.push(s);
        }
        return res;
    },
    _parseOptionToSeries: function() {
        var colori = 0, s, op = this.options;
        for (i = 0; i < this.series.length; ++i) {
            s = this.series[i];  
            if (s.color == null) {
                s.color = mstar.flotUtil.colorToRGB(this.options.colors[colori++]);
            } else if (typeof s.color == "number") {
                s.color = mstar.flotUtil.colorToRGB(this.options.colors[s.color]);
            }
            // copy the rest
            s.lines = $.extend(true, {},op.lines, s.lines);
            s.points = $.extend(true, {},op.points, s.points);
            s.bars = $.extend(true, {},op.bars, s.bars);
            s.OLHC = $.extend(true,{},op.OLHC,s.OLHC);
            s.imagePoints = $.extend(true,{},op.imagePoints,s.imagePoints);
            s.candleStick = $.extend(true,{},op.candleStick,s.candleStick);
			s.volumeByPrice = $.extend(true,{},op.volumeByPrice,s.volumeByPrice);
			s.otherInfo = $.extend(true,{},op.otherInfo,s.otherInfo);
            if (s.xaxis && s.xaxis == 2){
                s.xaxis = this.axes.x2axis;
            } else {
                s.xaxis = this.axes.xaxis;
            }
            if (s.yaxis && s.yaxis == 2) {
                s.yaxis = this.axes.y2axis;
            } else {
                s.yaxis = $.extend(this.axes.yaxis,this.options.yaxis);
            }
        }
    },
    _calculateAxisExtreme: function() {   // get the maximum and minimum of the xaisx and yaisx.
        var topSentry = Number.POSITIVE_INFINITY, bottomSentry = Number.NEGATIVE_INFINITY, axis;
        for (axis in this.axes) {
            this.axes[axis].datamin = topSentry;
            this.axes[axis].datamax = bottomSentry;
            this.axes[axis].used = false;
        }
        var data, axisx, axisy, mindelta = 0, maxdelta = 0;
        for (var i = 0; i < this.series.length; ++i) {
            data = this.series[i].data, axisx = this.series[i].xaxis, axisy = this.series[i].yaxis;
            if((this.series[i].imagePoints && this.series[i].imagePoints.show) ||(this.series[i].volumeByPrice&&this.series[i].volumeByPrice.show)) {
                continue;   
            }
            axisx.used = axisy.used = true;
            var x, ymax, ymin, isOLHC = false;
			if((this.series[i].OLHC.show || this.series[i].candleStick.show)){
                isOLHC = true;//y = data[j][2]; ymindelta= data[j][3]; ymin = data[j][3];
            }  
            for (var j = 0; j < data.length; ++j) {
                if (data[j] == null) {
                    continue;
                }
                x = data[j][0], ymax = isOLHC?data[j][2]:data[j][1], ymin = isOLHC?data[j][3]:data[j][1];//Jacye CHLO
                // convert to number
                if (x != null && !isNaN(x = +x)) {
                    if (x + mindelta < axisx.datamin)
                        axisx.datamin = x + mindelta;
                    if (x + maxdelta > axisx.datamax)
                        axisx.datamax = x + maxdelta;
                }         
                if (ymin!=null&&ymin < axisy.datamin && !isNaN(ymin))
                    axisy.datamin = ymin;
                if (ymax!=null&& ymax > axisy.datamax&&!isNaN(ymax))
                    axisy.datamax = ymax;
            }
        }
        for (axis in this.axes) {
            if (this.axes[axis].datamin == topSentry)
                this.axes[axis].datamin = 0;
            if (this.axes[axis].datamax == bottomSentry)
                this.axes[axis].datamax = 1;
        }
    },
    _calculateAndMeasure: function() {
		var axis,op;
        for (var ax in this.axes) {
			axis =this.axes[ax],op =this.options[ax] ;
			this._calculateAxisRange(axis, op);
        	this._prepareTickGeneration(axis, op);
        	this._generateTicks(axis, op);
            this._calculateP2CC2P(axis, op,axis);
        } 
       this._calculateSpacing();
    },
    _calculateP2CC2P: function(axis, op) {
        // add transformation helpers
        if (axis == this.axes.xaxis || axis == this.axes.x2axis) {    
            axis.p2c = function (p) { return (p - axis.min) * axis.scale; }; // data point to canvas coordinate
            axis.c2p = function (c) { return axis.min + c / axis.scale; }; // canvas coordinate to data point
        }
        else {//jacky 2.4  // y axis
            if(axis.scaleType == 1){
				axis.p2c = function(p){ return ((Math.log(axis.max)-Math.log(p+axis.dx))*axis.scale);}
				//axis.c2p = function(c){return (Math.log(axis.max)-Math.log(c)/axis.scale - axis.dx);}
				axis.c2p = function(c){return Math.exp(Math.log(axis.max)-c/axis.scale)-axis.dx;}
			} else {
				axis.p2c = function(p){return (axis.max - p) * axis.scale; };
				axis.c2p = function(c){return axis.max - c / axis.scale; }
			}	
        }
    },
    _calculateAxisRange: function(axis, axisOptions) {
        var min = axisOptions.min != null ? axisOptions.min : axis.datamin;
        var max = axisOptions.max != null ? axisOptions.max : axis.datamax;
        if(axisOptions.posStyle) axis.posStyle = axisOptions.posStyle; // Jacye.
        if (max - min == 0.0) { // degenerate case
            var widen;
            if (max == 0.0){
                widen = 1.0;
            } else {
                widen = 0.01;
            }
            min -= widen;
            max += widen;
        } else {                             
            var margin = axisOptions.autoscaleMargin;        // consider autoscaling
            if (margin != null) {
                if (axisOptions.min == null) {
                    min -= (max - min) * margin;
                    if (min < 0 && axis.datamin >= 0) {    // make sure we don't go below zero if all values are positive
                        min = 0;
                    }
                }
                if (axisOptions.max == null) {
                    max += (max - min) * margin;
                    if (max > 0 && axis.datamax <= 0) {
                        max = 0;
                    }
                }
            }
        }
		if(!isNaN(axisOptions.minBottomLine)){
			min=Math.min(min,axisOptions.minBottomLine);
		}
		if(!isNaN(axisOptions.minTopLine)){
			max=Math.max(max,axisOptions.minTopLine);
		}
        axis.min = min;
        axis.max = max;
		if(axis.scaleType == 1){//jacky 2.4
        	axis.dx = 0;
			if(axis.min <1){
				axis.dx = 1 - axis.min;    // ajust the min.
				axis.min = 1;
				axis.max = 	axis.max+axis.dx;
			}	
		}
    },
    _generateTicks: function(axis, axisOptions) {
        axis.ticks = [];
        if (!axis.used) {
            return;
        }
        if (axisOptions.showLabel) {
            axis.showLabel = axisOptions.showLabel;        // Jacye.
        } 
        if (axisOptions.ticks == null) {
            axis.ticks = axis.tickGenerator(axis);
        } else if (typeof axisOptions.ticks == "number") {
            if (axisOptions.ticks > 0) {
                axis.ticks = axis.tickGenerator(axis);
            }    
        } else if (axisOptions.ticks) {
            var ticks = axisOptions.ticks;
            if ($.isFunction(ticks)) {
                // generate the ticks
                ticks = ticks({ min: axis.min, max: axis.max });
            }
            // clean up the user-supplied ticks, copy them over
            var i, v;
            for (i = 0; i < ticks.length; ++i) {
                var label = null;
                var t = ticks[i];
                if (typeof t == "object") {
                    v = t[0];
                    if (t.length > 1)
                        label = t[1];
                } else {
                    v = t;
                }    
                if (label == null) {
                    label = axis.tickFormatter(v, axis);
                }
                axis.ticks[i] = { v: v, label: label };
            }
        }
        if (axisOptions.autoscaleMargin != null && axis.ticks.length > 0) {
            // snap to ticks
            if (axisOptions.min == null) 
				if(axis.scaleType != 1 || axis.ticks[0].v > 0){
					axis.min = Math.min(axis.min, axis.ticks[0].v);
		 		}
            if (axisOptions.max == null && axis.ticks.length > 1) {
                //axis.max = Math.min(axis.max, axis.ticks[axis.ticks.length - 1].v);  // change by Jacye. max
                var dx = 0;
                if (axis.ticks.length > 1) {
                   dx = axis.tickSize / 2;
                   axis.max = Math.max(axis.max, axis.ticks[axis.ticks.length - 1].v - dx);
                } else {
                   axis.max = Math.min(axis.max, axis.ticks[axis.ticks.length - 1].v);
                }  
            }               
        }
    },
    _calculateSpacing: function() {     
        // get the most space needed around the grid for things
        // that may stick out
        var grid = this.options.grid, oaxes = this.axes;
        var maxOutset = grid.borderWidth / 2;
        for (i = 0; i < this.series.length; ++i){
			if(typeof(this.series[i].points)!="undefined"){
				maxOutset = Math.max(maxOutset, 2 * (this.series[i].points.radius + this.series[i].points.lineWidth/2));
			}
        }
        this.plotOffset.left = this.plotOffset.right = this.plotOffset.top = this.plotOffset.bottom = 2;//maxOutset; Jacye
        if (oaxes.xaxis.showLabel && oaxes.xaxis.labelHeight > 0 && !oaxes.xaxis.posStyle && !oaxes.xaxis.posStyle != "inner") {//Jacye
            this.plotOffset.bottom = Math.max(0, oaxes.xaxis.labelHeight + 2*grid.labelMargin);//jacye
        }
        if (oaxes.yaxis.showLabel && oaxes.yaxis.labelWidth > 0) {    //Jacye
            this.plotOffset.left = Math.max(maxOutset, oaxes.yaxis.labelWidth + grid.labelMargin);
        }
        if (oaxes.x2axis.showLabel&&oaxes.x2axis.labelHeight > 0){    //Jacye
            this.plotOffset.top = Math.max(0, oaxes.x2axis.labelHeight + grid.labelMargin);//Jacye
        }
        if (oaxes.y2axis.showLabel && oaxes.y2axis.labelWidth > 0){   //Jacye
            this.plotOffset.right = Math.max(maxOutset, oaxes.y2axis.labelWidth + grid.labelMargin);
        }
		
        this.plotWidth = this.canvasWidth - this.plotOffset.left - this.plotOffset.right;
        this.plotHeight = this.canvasHeight - this.plotOffset.bottom - this.plotOffset.top;
		if(this.options.yaxis.align=="right"){
			this.plotOffset.left =0;
		}
		//this.plotOffset.left = 0;
        // precompute how much the axis is scaling a point in canvas space
        oaxes.xaxis.scale = parseFloat((this.plotWidth / (oaxes.xaxis.max - oaxes.xaxis.min)).toFixed(5));
		//jacky 2.4
		if(oaxes.yaxis.scaleType == 1){
			oaxes.yaxis.scale = parseFloat(this.plotHeight /(Math.log(oaxes.yaxis.max)-Math.log(oaxes.yaxis.min+oaxes.yaxis.dx)));
		}else{
			oaxes.yaxis.scale = parseFloat((this.plotHeight / (oaxes.yaxis.max - oaxes.yaxis.min)).toFixed(5));
		}
        oaxes.x2axis.scale = this.plotWidth / (oaxes.x2axis.max - oaxes.x2axis.min);
        oaxes.y2axis.scale = this.plotHeight / (oaxes.y2axis.max - oaxes.y2axis.min);
    },
    _prepareTickGeneration: function(axis, axisOptions) {
        // estimate number of ticks
        var noTicks;
        if (typeof axisOptions.ticks == "number" && axisOptions.ticks > 0)
            noTicks = axisOptions.ticks;
        else if (axis == this.axes.xaxis || axis == this.axes.x2axis)
            noTicks = this.canvasWidth / 100;
        else
            noTicks = this.canvasHeight / 60;
        
        var delta = (axis.max - axis.min) / noTicks;
        var size, generator, unit, formatter, i, magn, norm;
        if (axisOptions.mode == "time") {
			
        } else {
            // pretty rounding of base-10 numbers
            var maxDec = axisOptions.tickDecimals;
            var dec = -Math.floor(Math.log(delta) / Math.LN10);
            if (maxDec != null && dec > maxDec)
                dec = maxDec;           
            magn = Math.pow(10, -dec);
            norm = delta / magn; // norm is between 1.0 and 10.0         
            if (norm < 1.5)
                size = 1;
            else if (norm < 3) {
                size = 2;
                // special case for 2.5, requires an extra decimal
                if (norm > 2.25 && (maxDec == null || dec + 1 <= maxDec)) {
                    size = 2.5;
                    ++dec;
                }
            }
            else if (norm < 7.5)
                size = 5;
            else
                size = 10;

            size *= magn;
            
            if (axisOptions.minTickSize != null && size < axisOptions.minTickSize)
                size = axisOptions.minTickSize;
            if (axisOptions.tickSize != null)
                size = axisOptions.tickSize;        
            axis.tickDecimals = Math.max(0, (maxDec != null) ? maxDec : dec);         
            generator = function (axis) {
                var ticks = [];

                // spew out all possible ticks
				var dxx = (axis.scaleType == 1&&axis.dx)?axis.dx:0;
                var start = mstar.flotUtil.floorInBase(axis.min, axis.tickSize),
                    i = 0, v = Number.NaN, prev;
                	do {
                        prev = v;
                        v = start + i * axis.tickSize - dxx;
                        ticks.push({ v: v, label: axis.tickFormatter(v, axis)+"" });
                        ++i;
                    } while (v < (axis.max-dxx) && v != prev);	
                return ticks;
            };
            formatter = function (v, axis) {         //formate y xiax
            	if(v>1000&&axis.unit=="k"){  // 
            	    var u = typeof(QS_Lang.Chart.txt)=="undefined"?" k":(" "+QS_Lang.Chart.txt.shortKilo);
					return (typeof(QS_NumFmt)=="undefined"?(v/1000).toFixed(2):QS_NumFmt.Fmt2(v/1000,true,"",2))+u;
				}
                return typeof(QS_NumFmt)!="undefined"?QS_NumFmt.Fmt2(v,true," ",axis.tickDecimals):v.toFixed(axis.tickDecimals);
            };
        }
        axis.tickSize = unit ? [size, unit] : size;
        axis.tickGenerator = generator;
        if ($.isFunction(axisOptions.tickFormatter))
            axis.tickFormatter = function (v, axis) { return "" + axisOptions.tickFormatter(v, axis); };
        else
            axis.tickFormatter = formatter;
        if (axisOptions.labelWidth != null)
            axis.labelWidth = axisOptions.labelWidth;
        if (axisOptions.labelHeight != null)
            axis.labelHeight = axisOptions.labelHeight;
    },
    _getAxisLabelHtml: function(ax) { 
        var axis ,tp,tick, str = "", oset = this.plotOffset;
        if(ax == "xaxis") { 
            axis = this.axes.xaxis; tp = this.plotOffset.top + this.plotHeight + this.options.grid.labelMargin;
            if(axis.showLabel) {
				var lx;
                for (var i = 0; i < axis.ticks.length; ++i) { 
                    tick = axis.ticks[i],lx =tick.s,txt = tick.label+"";// axis.p2c(tick.v);
                    if (!tick.label || tick.v < axis.min || tick.v > axis.max) {
                        continue;    
                    }
					if(!tick.on||(i==0&&(txt.length*7+4)>tick.w)||(i==axis.ticks.length-1&&(txt.length*7+4)>tick.w)){
						 continue;
					}
					
                    str += '<div style="position:absolute;text-align:'+(this.axes.xaxis.alternate?"left":this.options.xaxis.textAlign)+'; top:' + (axis.posStyle && axis.posStyle=="inner"?(tp-23):tp)  + 'px;left:' + (oset.left + lx ) + 'px;width:' + tick.w + 'px;" class="tickLabel tickLabel-x" >' + tick.label + "</div>";
                }
            }
        } else if(ax == "yaxis") { 
            axis = this.axes.yaxis;
            if(axis.showLabel) {
                for (var i = 0; i < axis.ticks.length; ++i) {
                    tick = axis.ticks[i];
					//jacky  remove || tick.v < axis.min
                    if (!tick.label  || tick.v > axis.max) continue;  			
					var ttop = (oset.top + axis.p2c(tick.v) - axis.labelHeight-4); //jacky prevent out of the border
                    if(ttop<=-2){
						ttop=0;
					}else if((ttop+axis.labelHeight)>this.plotHeight){
						continue;
						//ttop = this.plotHeight-axis.labelHeight;
					}
					str+='<div style="position:absolute;top:' + ttop + 'px;right:' + (oset.right +((this.options.yaxis.align!="right")?this.plotWidth:0)+this.options.grid.labelMargin) + 'px;width:' + axis.labelWidth + 'px;text-align:right" class="tickLabel">' + tick.label + "</div>";
                }
            }
        } else if(ax == "x2axis") {
            axis = this.axes.x2axis;   
            if(axis.showLabel){
                for (var i = 0; i < axis.ticks.length; ++i) {
                    tick = axis.ticks[i];
                    if (!tick.label || tick.v < axis.min || tick.v > axis.max) continue;    
                    str+='<div style="position:absolute;bottom:' + (oset.bottom + this.plotHeight + this.options.grid.labelMargin) + 'px;left:' + (oset.left + axis.p2c(tick.v) - axis.labelWidth/2) + 'px;width:' + axis.labelWidth + 'px;text-align:center" class="tickLabel">' + tick.label + '</div>';
                }
            }
        } else if(ax == "y2axis") {
            axis = this.axes.y2axis;
            if(axis.showLabel){
                for (var i = 0; i < axis.ticks.length; ++i) {
                    tick = axis.ticks[i]; 
                    if (!tick.label || tick.v < axis.min || tick.v > axis.max) continue;            
                    str+='<div style="position:absolute;top:' + (oset.top + axis.p2c(tick.v) - axis.labelHeight/2) + 'px;left:' + (oset.left + this.plotWidth + this.options.grid.labelMargin) +'px;width:' + axis.labelWidth + 'px;text-align:left" class="tickLabel">' + tick.label + '</div>';
                }
            }
        }
        return str;
    },
    _insertAxisLabels: function() {
        var $TickerContainer = this.target.find(".tickLabels"), html = '';
        if ($TickerContainer.length < 1) {
            this.target.append('<div class="tickLabels" style="color:' + this.options.grid.color + '"></div>');   
        } else {
            $TickerContainer.html("");
        } 
        html += this._getAxisLabelHtml("xaxis");
        html += this._getAxisLabelHtml("x2axis");
        html += this._getAxisLabelHtml("yaxis");
        html += this._getAxisLabelHtml("y2axis");
        this.target.find(".tickLabels").html(html);
        $TickerContainer = null;
        html = null;
    },
    _drawGrid: function() {
        var i, cx = this.ctx, oset = this.plotOffset;
        cx.save();
        cx.clearRect(0, 0, this.canvasWidth, this.canvasHeight);
        if (this.options.grid.borderWidth) {
            this._setCanvasContext(cx,{ss:this.options.grid.tickColor});
            cx.beginPath();
            cx.moveTo(0,cx.lineWidth/2);//(this.options.yaxis.align!="right")?
            cx.lineTo(this.canvasWidth + cx.lineWidth,cx.lineWidth/2);
			if(this.options.yaxis.align=="right"){
	            cx.moveTo(((this.options.yaxis.align!="right")?oset.left:this.plotWidth) + cx.lineWidth/2,0);
	            cx.lineTo(((this.options.yaxis.align!="right")?oset.left:this.plotWidth) + cx.lineWidth/2,(this.axes.xaxis.showLabel?(this.canvasHeight-1):this.plotHeight + oset.top));
			}
            cx.stroke();
			cx.strokeStyle = this.options.grid.bottomColor;  // draw bottom line
			cx.beginPath();
	        cx.moveTo(this.canvasWidth  + cx.lineWidth,this.plotHeight + oset.top + cx.lineWidth/2);
	        cx.lineTo(0,this.plotHeight + oset.top + cx.lineWidth/2);
			if(this.axes.xaxis.showLabel && this.axes.xaxis.posStyle!="inner"){
				cx.moveTo(0,this.canvasHeight - cx.lineWidth/2);
				cx.lineTo(this.canvasWidth,this.canvasHeight-cx.lineWidth/2);	
			}
			cx.stroke();
        }
		if(this.axes.xaxis.showLabel&&this.options.grid._borderColor!=null){//
			cx.beginPath();
			this._setCanvasContext(cx,{ss:this.options.grid._borderColor});
			cx.rect((this.options.yaxis.align=="right"?1:oset.left),0,this.plotWidth,this.plotHeight+oset.top);
			cx.stroke();
		}
		
        cx.translate(oset.left, oset.top);
        // draw background, if any
        if (this.options.grid.backgroundColor) {
            cx.fillStyle = this.options.grid.backgroundColor;
            cx.fillRect(0, 0, this.plotWidth, this.plotHeight);
        }
        // draw the inner grid
        cx.lineWidth = 1;
        cx.strokeStyle = this.options.grid.tickColor;
        cx.beginPath();
        var v, axis = this.axes.xaxis;
		var hh = axis.showLabel?(this.canvasHeight-3):this.plotHeight,tx=0;
		var totalLen = 0,ion =0,llen=0;
		if(axis.ticks.length>0){
			var tempLen = Math.round(axis.ticks.length/2);
			if(tempLen>=axis.ticks.length){
				tempLen =axis.ticks.length-1;
			}
			llen=(this.axes.xaxis.ticks[tempLen].label+"").length*7+4;
		}
		var di = Math.ceil(axis.ticks.length/(this.plotWidth/llen));
		this.axes.xaxis.alternate=false;
		var dk = 0,avgl = 0,dkk=0,lasti=0;
        for (i = 0; i < axis.ticks.length; ++i) {
            v = axis.ticks[i].v;
			this.axes.xaxis.ticks[i].on = false;
			if(isNaN(v)||axis.ticks[i].label==""){
				continue; 
			}
			var tx = Math.floor(axis.p2c(v));;
			if(dk%di==0){
				this.axes.xaxis.ticks[i].s = tx;
				this.axes.xaxis.ticks[i].on = true;
				if(avgl==0&&dkk==1){
					avgl = this.axes.xaxis.ticks[i].s-this.axes.xaxis.ticks[i-di].s;
					this.axes.xaxis.ticks[i-di].w=avgl;
				}
				if(avgl!=0&&dkk==2){
					avgl = this.axes.xaxis.ticks[i].s-this.axes.xaxis.ticks[i-di].s;
					this.axes.xaxis.ticks[i-di].w=avgl;
				}
				this.axes.xaxis.ticks[i].w=avgl;
				cx.moveTo(tx + cx.lineWidth/2, -1);
		        cx.lineTo(tx + cx.lineWidth/2, hh);
				dkk++;
				lasti = i;
			}else{
				cx.moveTo(tx + cx.lineWidth/2, -1);
		        cx.lineTo(tx + cx.lineWidth/2, this.plotHeight);
			}
			if(i==axis.ticks.length-1){
				var lasttick = this.axes.xaxis.ticks[lasti];
				var lastdx =this.plotWidth -lasttick.s;
				if(lastdx<lasttick.w){
					lasttick.w = lastdx;
				}
				if(lastdx<llen){  // width of last last label less than the length of label, hide the label.
					lasttick.on = false;
				}
			}
			dk++;
            if (v <= axis.min || v >= axis.max){
				continue; 
			}
        }
		if(di>1){
			this.options.xaxis.textAlign="left";
		}
        axis = this.axes.yaxis;
        for (i = 0; i < axis.ticks.length; ++i) {
            v = axis.ticks[i].v;
            if (isNaN(v) || v <= axis.min || v >= axis.max)
                continue;
            cx.moveTo(this.plotOffset.left*(-1), Math.floor(axis.p2c(v)) + cx.lineWidth/2);
            cx.lineTo(this.canvasWidth, Math.floor(axis.p2c(v)) + cx.lineWidth/2);
        }
        axis = this.axes.x2axis;
        for (i = 0; i < axis.ticks.length; ++i) {
            v = axis.ticks[i].v;
            if (v <= axis.min || v >= axis.max)
                continue;

            cx.moveTo(Math.floor(axis.p2c(v)) + cx.lineWidth/2, -5);
            cx.lineTo(Math.floor(axis.p2c(v)) + cx.lineWidth/2, 5);
        }
        axis = this.axes.y2axis;
        for (i = 0; i < axis.ticks.length; ++i) {
            v = axis.ticks[i].v;
            if (v <= axis.min || v >= axis.max)
                continue;
            cx.moveTo(this.plotWidth-5, Math.floor(axis.p2c(v)) + cx.lineWidth/2);
            cx.lineTo(this.plotWidth+5, Math.floor(axis.p2c(v)) + cx.lineWidth/2);
        }
        if (!this.options.showGridLines) {
            return;
        }
        cx.stroke();
        cx.restore();
    },
    _setFillStyle: function(obj, seriesColor) {
        if (!obj.fill) {
            return;
        }
		if(typeof(obj.fillColor)!="undefined"&&obj.fillColor!=null){
			this.ctx.fillStyle=mstar.flotUtil.colorToRGB(obj.fillColor,typeof(QS_Style)=="undefined"?0.7:QS_Style.flot.alpha);
		}else{
			this.ctx.fillStyle=mstar.flotUtil.colorToRGB(seriesColor,typeof(QS_Style)=="undefined"?0.7:QS_Style.flot.alpha);
		}
    },
    _getDx: function(lg) {
        if (this.plotWidth <= 0) {
            dx = 1;
        } else {
            dx = Math.ceil(lg/this.plotWidth);
        }
        return dx;
    },
    _plotLine: function(data, offset, axisx, axisy) {
        var prev, cur = null, drawx = null, drawy = null;
        var lg  = data.length;
        var dx = this._getDx(lg); 
        var x1, y1, x2, y2;
        this.ctx.beginPath();
        for (var i = 0; i < lg; i+=dx) {                    
            prev = cur;
            if (data[i] != null && !isNaN(data[i][1])) {
                cur = data[i];                                      // update by Jacye
            } else {
                continue;
            }
            if (cur == null)
                continue;             
            if(prev != null ) {
                x1 = prev[0], y1 = prev[1];
            }
            x2 = cur[0], y2 = cur[1];
            drawx = axisx.p2c(x2);
            drawy = axisy.p2c(y2) + offset;
            if(!isNaN(drawx)){
				if (prev == null) { // the first point or the same point.
                	this.ctx.moveTo(drawx, drawy);
           		 } else {     // different points
               	    this.ctx.lineTo(drawx, drawy);
            	}
			}
        }
        this.ctx.stroke();
    },
    _plotDot: function(data, offset, axisx, axisy,dot) {
        var prev, cur = null, drawx = null, drawy = null;
        var lg  = data.length;
        var dx = this._getDx(lg); 
        var x1, y1, x2, y2;
		this.ctx.beginPath();
		this._setCanvasContext(this.ctx,{ss:dot.color,fs:dot.color});
        for (var i = 0; i < lg; i+=dx) {                    
            prev = cur;
            if (data[i] != null && !isNaN(data[i][1])) {
                cur = data[i];                                      // update by Jacye
            } else {
                continue;
            }
            if (cur == null)
                continue;             
            x2 = cur[0], y2 = cur[1];
            drawx = axisx.p2c(x2);
            drawy = axisy.p2c(y2) + offset;
            if(!isNaN(drawx)){
				 this.ctx.moveTo(drawx,drawy);    
               	 this.ctx.arc(drawx, drawy,dot.radius,0,2*Math.PI,true);
			}
        }
        if (dot.fill) {
            this.ctx.fill();
        } else {
            this.ctx.stroke();
        }
		this.ctx.restore();
    },
    _plotAboveBelow: function(data, offset, axisx, axisy,ab) {
		if(!isNaN(ab.midLineValue)){
			data.unshift([data[0][0],ab.midLineValue]);
		}
        var prev, cur = null, drawx = null, drawy = null;
        var lg  = data.length;
        var dx = this._getDx(lg);
        var x1, y1, x2, y2;
        
		var arr = [],ai = 0;
		var aa = [],ba=[],trend = 0;
		var k = 0,b = 0;
        for (var i = 0; i < lg; i+=dx) {                    
            prev = cur;
            if (data[i] != null && !isNaN(data[i][1])) {
                cur = data[i];                                      // update by Jacye
            } else {
                continue;
            }
            if (cur == null)
                continue;             
            if(prev != null ) {
                x1 = prev[0], y1 = prev[1];
            }
            x2 = cur[0], y2 = cur[1];
            drawx = axisx.p2c(x2);
            drawy = axisy.p2c(y2) + offset;
            if(!isNaN(drawx)){
				if (prev == null) { // the first point or the same point.
                	arr[0]=[drawx, drawy];
           		 } else {     // different points
               	 	arr[ai]=[drawx, drawy];
					if(trend==0){
						if(drawy<arr[0][1]){
							aa.push([arr[0][0],arr[0][1]]);
							aa.push([arr[ai][0],arr[ai][1]]);
							trend =1;
						}else if(drawy>arr[0][1]){
							ba.push([arr[0][0],arr[0][1]]);
							ba.push([arr[ai][0],arr[ai][1]]);
							trend =-1;
						}else{
							aa.push([arr[0][0],arr[0][1]]);
							ba.push([arr[0][0],arr[0][1]]);
							aa.push([arr[ai][0],arr[ai][1]]);
							ba.push([arr[ai][0],arr[ai][1]]);
							trend =0;
						}
					}else{
						if(drawy<arr[0][1]&&trend==1){
							aa.push([arr[ai][0],arr[ai][1]]);
							trend=1;
						}else if(drawy>arr[0][1]&&trend==-1){
							ba.push([arr[ai][0],arr[ai][1]]);
							trend =-1;
						}else if(drawy==arr[0][1]){
							aa.push([arr[ai][0],arr[ai][1]]);
							ba.push([arr[ai][0],arr[ai][1]]);
						}else{
							k = (drawy-arr[ai-1][1])/(drawx-arr[ai-1][0]);
							b = (arr[ai-1][0]*drawy-drawx*arr[ai-1][1])/(arr[ai-1][0]-drawx);
							var xxx = (arr[0][1]-b)/k;
							aa.push([xxx,arr[0][1]]);
							ba.push([xxx,arr[0][1]]);
							if(trend==-1){
								aa.push([arr[ai][0],arr[ai][1]]);
							}else{
								ba.push([arr[ai][0],arr[ai][1]]);
							}
							trend = -trend;
						}
					}
            	}
				ai++
			}
        }
		aa.push([arr[arr.length-1][0],arr[0][1]]);
		ba.push([arr[arr.length-1][0],arr[0][1]]);
			
		var start=0;
		if(!ab.bHasCloseLine){
			start=1; 
		}
		
		//above stroke
		this.ctx.beginPath();
		this.ctx.strokeStyle=mstar.flotUtil.colorToRGB(ab.aColor);
		for(var i = start;i<aa.length-start;i++){
			if(i==start){
				this.ctx.moveTo(aa[i][0],aa[i][1]);
			}else{
				this.ctx.lineTo(aa[i][0],aa[i][1]);
			}
		}
		this.ctx.stroke();
		
		//above fill
		this.ctx.beginPath();
		this.ctx.fillStyle=mstar.flotUtil.colorToRGB(ab.aFillColor||ab.aColor,0.7);
//		this.ctx.strokeStyle=mstar.flotUtil.colorToRGB(ab.aColor);
		for(var i = 0;i<aa.length;i++){
			if(i==0){
				this.ctx.moveTo(aa[i][0],aa[i][1]);
			}else{
				this.ctx.lineTo(aa[i][0],aa[i][1]);
			}
		}
		this.ctx.fill();
//        this.ctx.stroke();
		
		//below stroke
		this.ctx.beginPath();
		this.ctx.strokeStyle=mstar.flotUtil.colorToRGB(ab.bColor);
		for(var i = start;i<ba.length-start;i++){
			if(i==start){
				this.ctx.moveTo(ba[i][0],ba[i][1]);
			}else{
				this.ctx.lineTo(ba[i][0],ba[i][1]);
			}
		}
		this.ctx.stroke();
		
		//below fill
		this.ctx.beginPath();
		this.ctx.fillStyle=mstar.flotUtil.colorToRGB(ab.bFillColor||ab.bColor,0.7);
//		this.ctx.strokeStyle=mstar.flotUtil.colorToRGB(ab.bColor);
		for(var i = 0;i<ba.length;i++){
			if(i==0){
				this.ctx.moveTo(ba[i][0],ba[i][1]);
			}else{
				this.ctx.lineTo(ba[i][0],ba[i][1]);
			}
		}
		this.ctx.fill();
 //       this.ctx.stroke();
		
		//midline
		this.ctx.beginPath();
		this.ctx.strokeStyle=mstar.flotUtil.colorToRGB(ab.mColor);
		this.ctx.moveTo(arr[0][0],arr[0][1]);
		this.ctx.lineTo(arr[arr.length-1][0]+2,arr[0][1]);
		this.ctx.stroke();
		if(!isNaN(ab.midLineValue)){
			data.shift();
		}
    },
    _plotPoints: function(data, radius, fill, axisx, axisy) {
        var x, y, px, py, mp, lg = data.length;
        var cx = this.ctx;
        cx.beginPath();
        for (var i = 0; i < lg; ++i) {
            if (data[i] == null || isNaN(data[i][1])) {
                continue;   
            }      
            x = data[i][0], y = data[i][1];
            px = axisx.p2c(x); py = axisy.p2c(y);
            mp = 2 * Math.PI;
            if (x < axisx.min || x > axisx.max || y < axisy.min || y > axisy.max) {
                continue;
            }
            cx.moveTo(px,py);    
            cx.arc(px, py, radius, 0, mp, true);      
        }
        if (fill) {
           cx.fill(); 
        }
        cx.stroke();
    },
	_plotVolumeByPrice: function(data, offset, axisx, axisy) {
        this.ctx.beginPath();
		var arr = data,min = arr[1][0],max = arr[1][1];
		var len = Math.abs(axisy.p2c(min)-axisy.p2c(max));
		var hei = (len-39)/14;
		var high = Math.max(axisy.p2c(min),axisy.p2c(max));
		this.volumeByPrice.data =arr;
		var scale = (this.plotWidth*this.volumeByPrice.scale)/arr[2],t=null,loc;
		this.volumeByPrice.area.length=0;
		for(var i = 0;i<14;i++){
			loc = high-(i+1)*hei-i*3;
			t =[0,loc,arr[0][i][2]*scale,hei];
			this.ctx.rect(t[0],t[1],t[2],t[3]);
			this.volumeByPrice.area.push(t);
		}
        this.ctx.fill();
    },
    _plotLineArea: function(data, axisx, axisy) {
        var prev, cur = null;             
        var bottom = axisy.min;//Math.min(Math.max(0, axisy.min), axisy.max);
        var top, lastX = 0;
		var lg  = data.length;
		var dx = this._getDx(lg); 
        var areaOpen = false;     
        var x1,y1,x2,y2;        
        for (var i = 0; i < data.length; i+=dx) {
            prev = cur;
         	if (data[i] != null && !isNaN(data[i][1])) {
                cur = data[i];                                      // update by Jacye
            } else {
                continue;
            }
            if (areaOpen && prev != null && cur == null) {
                // close area
                ctx.lineTo(axisx.p2c(lastX), axisy.p2c(bottom));
                ctx.fill();
                areaOpen = false;
                continue;
            }
            if (cur == null)
                continue;
			if(prev!=null){
				x1 = prev[0], y1 = prev[1];
			}                  
            x2 = cur[0], y2 = cur[1];
			if (!isNaN(x2)) {
				if (!areaOpen) {
					// open area
					this.ctx.beginPath();
					this.ctx.moveTo(axisx.p2c(x2), axisy.p2c(bottom));
					areaOpen = true;
				}
				this.ctx.lineTo(axisx.p2c(x2), axisy.p2c(y2));
			}
            lastX = x2;
        }
        if (areaOpen) {
            this.ctx.lineTo(axisx.p2c(lastX), axisy.p2c(bottom));	
            this.ctx.fill();
        }
    },
    _plotOLHC: function(data, offset,axisx,axisy,olhcOption) {
        var oset = this.plotOffset, cx = this.ctx;   
	    var w = (this.canvasWidth - oset.left - oset.right-offset)/data.length;
	    if (w > olhcOption.maxBarWidth) w = olhcOption.maxBarWidth;
	    if (w < olhcOption.minBarWidth) w = olhcOption.minBarWidth;
	    olhcOption.barWidth = w;
	    var x, c, h, l, o, px, pc, po, pl, ph;
	    var maxW = this.canvasWidth - oset.left-oset.right - offset - w/2;
	    var lg = data.length;
	    cx.beginPath();
		for (var i = 0; i < lg; ++i) {
			if (data[i] == null) continue;
			var dt = data[i];
			if (dt.length < 6 || isNaN(dt[1]) || isNaN(dt[2]) || isNaN(dt[3]) || isNaN(dt[4])) {
			    continue;
			}
			x = dt[0], c = dt[1],h = dt[2], l = dt[3], o = dt[4];
			px = axisx.p2c(x),pc = axisy.p2c(c), po = axisy.p2c(o), pl = axisy.p2c(l), ph = axisy.p2c(h);
			if (i == 0 && px < w/2)  px = w/2;
			if (i == lg-1&& px > maxW) px = maxW;      			
			cx.moveTo(px,ph);
			cx.lineTo(px,pl);
			if(olhcOption.olhcType=="ohlc"){
				cx.moveTo(px,po);
				cx.lineTo(px-w/2,po);
			}
			cx.moveTo(px,pc);
			cx.lineTo(px+w/2,pc);      			
		}
		cx.stroke();
    },
    _drawCandleStick: function(px,po,pl,ph,pc,dt,aw,clo,ct) { 
        ct.moveTo(px-aw/2,po);
        ct.lineTo(px+aw/2,po);
        if (pc != po) {
            ct.lineTo(px+aw/2,pc);
            ct.lineTo(px-aw/2,pc);
            ct.lineTo(px-aw/2,po);
        }
        ct.moveTo(px,pl);
        var pM = po>pc?po:pc;
        var pL =  po>pc?pc:po;
        if (pl != pM) {
            ct.lineTo(px,pM);
        }
        ct.moveTo(px,ph);
        if(ph != pL) {
            ct.lineTo(px,pL);
        }
    },
    _drawColorCandle: function(pdata,clo,axisx,axisy,aw) {
        var filldata = [];
	    var lg = pdata.length;
	    var dt, x, c , h, l, o, px, pc, po, pl, ph;
	    var maxW = this.canvasWidth - this.plotOffset.right - this.plotOffset.left - aw/2;
	    var cx = this.ctx;
        cx.strokeStyle = clo;
        cx.lineWidth=1;
	    cx.beginPath();
	    for(var k = 0; k < lg; k++) { 
	        dt = pdata[k];
	        x=dt[0], c = dt[1],h = dt[2], l=dt[3], o = dt[4];
			px = axisx.p2c(x);
			pc = axisy.p2c(c), po = axisy.p2c(o), pl = axisy.p2c(l), ph = axisy.p2c(h);
			if (k == (lg-1) && px>maxW) {
			    px= maxW;
			}
			if (k == 0 && px < aw/2) {
			    px=aw/2;
			}
			if(c < o) { // close price <open price fill the bar
			    filldata.push([px,po,pc]);
			}
			this._drawCandleStick(px,po,pl,ph,pc,dt,aw,clo,this.ctx)
	    }
	    cx.stroke();
	    if (filldata.length > 0) { // filled the candlesticks which need to be filled.
	        cx.lineWidth = aw; 
	        cx.lineCap="butt";
	        cx.beginPath();
	        for (var j = 0;j < filldata.length; j++){ 
	            if(filldata[j][1] != filldata[j][2]) {
	                cx.moveTo(filldata[j][0],filldata[j][1]);
	                cx.lineTo(filldata[j][0],filldata[j][2]);
	            }
	        }
	        cx.stroke();
	    }
    },
    _plotCandleStick: function(data, offset, axisx,axisy,candleOption) {
        var maxwidth = (candleOption.maxCandleWidth==null)?16:candleOption.maxCandleWidth;
        var minwidth = (candleOption.minCandleWidth==null)?4:candleOption.minCandleWidth;
        var aw = Math.floor(0.7*(this.canvasWidth - this.plotOffset.left - this.plotOffset.right)/data.length);  	
        var upData = [],downData = [], dt;
        var lg = data.length;    
        if (aw < minwidth) aw = minwidth;
        if (aw > maxwidth) aw = maxwidth;
        candleOption.candleWidth = aw;
        for (var j = 0;j < lg ;j++) {
            dt = data[j];
            if (dt == null || dt.length<6 || isNaN(dt[1]) || isNaN(dt[2]) || isNaN(dt[3]) || isNaN(dt[4])) continue;
            if (dt[5] > 0) {    // up trend.
                upData.push(dt); 
            } else {
                downData.push(dt);
            }
        }
        this._drawColorCandle(upData,candleOption.upColor, axisx,axisy,aw);
        this._drawColorCandle(downData,candleOption.downColor, axisx,axisy,aw);		     
    },
    _drawBar: function(x, y, aw, offset, clo, axisx, axisy, c) {
        var drawLeft = false, drawRight = false, drawTop = false, drawBottom = false;
        var  bottom = 0, top = y, maxW = this.canvasWidth - this.plotOffset.right - this.plotOffset.left - offset - aw/2;
        var px = axisx.p2c(x);
        if (px > maxW) {
            px= maxW;
        }
    	if (px < aw/2) px=aw/2;
        if (aw <= 16) {
            c.lineWidth = aw;
            c.strokeStyle = clo;
            if (bottom != top) {
                c.moveTo(px, axisy.p2c(bottom) + offset);
                c.lineTo(px, axisy.p2c(top) + offset);
            }
        } else {
            c.lineWidth = 0;
            c.strokeStyle = clo;
            c.fillStyle = clo;
            c.beginPath();
            c.moveTo((px-aw/2), axisy.p2c(bottom) + offset);
            c.lineTo((px-aw/2), axisy.p2c(top) + offset);
            c.lineTo((px+aw/2), axisy.p2c(top) + offset);//c.lineTo(axisx.p2c(right), axisy.p2c(top) + offset);
            c.lineTo((px+aw/2), axisy.p2c(bottom) + offset);  //c.lineTo(axisx.p2c(right), axisy.p2c(bottom) + offset);
            c.fill();
        }
        // draw outline
        if (this.series[0].bars.outLine) {         //(drawLeft || drawRight || drawTop || drawBottom)
            c.beginPath();
            left = axisx.p2c(left);
            bottom = axisy.p2c(bottom);
            right = axisx.p2c(right);
            top = axisy.p2c(top);
            c.moveTo(left, bottom + offset);
            if (drawLeft)
                c.lineTo(left, top + offset);
            else
                c.moveTo(left, top + offset);
            if (drawTop)
                c.lineTo(right, top + offset);
            else
                c.moveTo(right, top + offset);
            if (drawRight)
                c.lineTo(right, bottom + offset);
            else
                c.moveTo(right, bottom + offset);
            if (drawBottom)
                c.lineTo(left, bottom + offset);
            else
                c.moveTo(left, bottom + offset);
            c.stroke();
        }
    },
    _plotBars: function(data, offset, op, axisx, axisy, color,dlg) {
        var maxwidth = (op.maxBarWidth==null)?16:op.maxBarWidth;
	    var minwidth = (op.minBarWidth==null)?4:op.minBarWidth;
	    var aw = Math.floor(0.7*(this.canvasWidth - this.plotOffset.left - this.plotOffset.right)/dlg);
	    var lg = data.length;      	    
	    if(aw < minwidth) aw = minwidth;
	    if(aw > maxwidth) aw = maxwidth;
	    op.barWidth = aw;
	    this.ctx.beginPath();
	    var ix = this._getDx(lg);
        for (var i = 0; i < lg; i+=ix) {
            if (data[i] == null||isNaN(data[i][1])) continue;             
            this._drawBar(data[i][0], data[i][1], aw, offset, color, axisx, axisy, this.ctx);
        }
        this.ctx.stroke();
    },
	_drawTriangle:function(x,y,ct){
		ct.lineWidth = 1;
		ct.beginPath();
		ct.moveTo(x,y);
		ct.lineTo(x-6.5,y-8);
		ct.lineTo(x+6.5,y-8);
		ct.lineTo(x+1,y-1);
		ct.fill();
		ct.beginPath();
		ct.moveTo(x-7.5,y-8);
		ct.lineTo(x,y);
		ct.lineTo(x+7.5,y-8);
		ct.stroke();
		
	},
	_drawRectangleImg:function(x,y,ct){
		ct.beginPath();
		ct.moveTo(x-6.5,y);
		ct.lineTo(x+6.5,y);
		ct.lineTo(x+6.5,y-12);
		ct.lineTo(x-6.5,y-12);
		ct.lineTo(x-6.5,y);
		ct.fill();
		ct.beginPath();
		ct.moveTo(x+7.5,y);
		ct.lineTo(x+7.5,y-13);
		ct.lineTo(x-7.5,y-13);
		ct.lineTo(x-7.5,y);
		ct.stroke();
	},
    _drawDividendImg: function(x,y,ct,f) {    
        ct.lineWidth = 1;
		ct.strokeStyle="rgb(255,255,255)";
		ct.fillStyle = "rgb(47,72,128)";
		if(f){
			this._drawTriangle(x,y,ct);
			y-=8;
		}
		this._drawRectangleImg(x,y,ct);
		y -=7;
		ct.beginPath();
		ct.lineWidth = 1.5;
        ct.arc(x-1,y+1,4,-Math.PI*3/5,Math.PI*3/5,false);
		ct.moveTo(x-2,y-3);
		ct.lineTo(x-2,y+5);
		ct.stroke();
    },      
    _drawSplitsImg: function(x,y,ct,f) {    
 		ct.lineWidth = 1;
		ct.fillStyle = "rgb(47,72,128)";
		ct.strokeStyle = "rgb(255,255,255)";
		if(f){
			this._drawTriangle(x,y,ct);
			y-=8;
		}
		this._drawRectangleImg(x,y,ct);
		y -=7;
		ct.beginPath();
		ct.lineWidth = 2;
        ct.arc(x,y-1,2,0,Math.PI/2,true);
		ct.arc(x,y+2.5,2,-Math.PI/2,Math.PI,false);
		ct.stroke();
    },
    _drawEarningsImg: function(x,y,ct,t,f) {    
        ct.lineWidth = 1;
		ct.strokeStyle = "rgb(255,255,255)";
		if (typeof(t) != "undefined") {
			if(t==0){
				ct.fillStyle = "rgb(255,0,0)";	
			}else{
				ct.fillStyle = "rgb(76,182,62)";
			}
		}
		if(f){
			this._drawTriangle(x,y,ct);
			y-=8;
		}
		this._drawRectangleImg(x,y,ct);
		y-=7;
		ct.beginPath();
		ct.moveTo(x-7,y-7);
		ct.lineTo(x-7,y+7);
		ct.lineTo(x,y+14);
		ct.lineTo(x+7,y+7);
		ct.lineTo(x+7,y-7);
		ct.lineTo(x-7,y-7);
		ct.stroke();
		ct.beginPath();
		ct.lineWidth = 1.5;
		ct.moveTo(x+2.5,y+5);
		ct.lineTo(x-2.5,y+5);
		ct.lineTo(x-2.5,y-3);
		ct.lineTo(x+2.5,y-3);
		ct.moveTo(x-2.5,y+1);
		ct.lineTo(x+2.5,y+1);		
		ct.stroke();
		ct.lineWidth = 2;
		ct.beginPath();
		ct.moveTo(x-3,y-3.5);
		ct.lineTo(x-3,y+5.5);
		ct.stroke();
    },
    _plotImages:function(data, offset, axisx, axisy) {
       var dt,  ty, px, py, lg = data.length,dl=0;
       for (var i = lg-1; i >=0; i--) {
	   		dt = data[i];
	       	if( typeof(dt)=="undefined") continue;
			px = axisx.p2c(dt[0]),py = this.plotHeight;
			for(var j =1;j<dt.length;j++){
				if(dt[j]==3){
					this._drawEarningsImg(px,py,this.ctx,0,j==1);
				}else if(dt[j]==4){
					this._drawEarningsImg(px,py,this.ctx,1,j==1);
				}else if(dt[j]==1){
					this._drawDividendImg(px,py,this.ctx,j==1);
				}else if(dt[j]==2){
					this._drawSplitsImg(px,py,this.ctx,j==1);
				}
				py -=j==1?21:13;
			}
			this.imgDataList[i]=py;
		}     		
	},	
	_setCanvasContext:function(ct,pt){
		ct.save();
		if(typeof(pt.cr)!="undefined"&&pt.cr.length>0){
			ct.clearRect(pt.cr[0],pt.cr[1],pt.cr[2],pt.cr[3]);
		}
		if(typeof(pt.tl)!="undefined"&&pt.tl.length>0){
			ct.translate(pt.tl[0],pt.tl[1]);
		}
        ct.lineJoin = typeof(pt.lj)=="undefined"?"round":pt.lj;
        ct.lineWidth = typeof(pt.lw)=="undefined"?1:pt.lw;
        ct.strokeStyle =typeof(pt.ss)=="undefined"?"rgb(100,100,100)":pt.ss;
		if(typeof(pt.ga)!="undefined"){
			ct.globalAlpha =pt.ga;
		}
		if(typeof(pt.fs)!="undefined"){
			ct.fillStyle =pt.fs;
		}	
	},
    _drawSeriesLines: function(series) {
        var cx = this.ctx;
		var lw = series.lineW == null?series.lines.lineWidth:series.lineW;
		this._setCanvasContext(cx,{lw:lw,tl:[this.plotOffset.left, this.plotOffset.top],ss:series.color});
        this._setFillStyle(series.lines, series.color);
		var type = series.lines.lineType, showLegend = series.showLegend, legendLabel = series.legendLabel;
		if(type=="line"){
			this._plotLine(series.data, 0, series.xaxis, series.yaxis);
		}else if(type=="mountain"){
			this._plotLineArea(series.data, series.xaxis, series.yaxis);
			//this._plotLine(series.data, 0, series.xaxis, series.yaxis);
			if (!series.lines.noLine) {
			this._plotLine(series.data, 0, series.xaxis, series.yaxis);
		}
		}else if(type=="dot"){
			this._plotDot(series.data, 0, series.xaxis, series.yaxis,series.lines.dot);
		}else if(type=="ab"){
			this._plotAboveBelow (series.data, 0, series.xaxis, series.yaxis,series.lines.ab);
		}
//        if (series.lines.fill) {
//            this._plotLineArea(series.data, series.xaxis, series.yaxis);
//        }
//        if (!series.lines.noLine) {
//			this._plotLine(series.data, 0, series.xaxis, series.yaxis);
//		}
        cx.restore();
		if(showLegend){
			if(series.data&&series.data.length){
				var d = series.data[series.data.length-1];
	            var x = series.xaxis.p2c(d[0]), y= series.yaxis.p2c(d[1]);
	            this._createLegend(isNaN(d[1])?"":(typeof(QS_NumFmt)!="undefined"?QS_NumFmt.Fmt2(d[1],true," ",series.yaxis.tickDecimals):d[1].toFixed(2)),legendLabel,x-150+this.plotOffset.left,y-18);
			}
			
		}
    },
    _drawSeriesOLHC: function(series){
		this._setCanvasContext(this.ctx,{tl:[this.plotOffset.left, this.plotOffset.top],ss:series.color});
        this._setFillStyle(series.OLHC, series.color);
        this._plotOLHC(series.data, 0, series.xaxis, series.yaxis,series.OLHC);
        this.ctx.restore();
    },
    _drawSeriesCandleStick: function(series) {
		this._setCanvasContext(this.ctx,{tl:[this.plotOffset.left, this.plotOffset.top],ss:series.color});
        this._setFillStyle(series.candleStick, series.color);
        this._plotCandleStick(series.data, 0, series.xaxis, series.yaxis,series.candleStick);
        this.ctx.restore();
    },
    _drawSeriesPoints: function(series) {
        var cx = this.ctx;
        var lw = series.lines.lineWidth;
        cx.save();
        cx.translate(this.plotOffset.left, this.plotOffset.top);
        cx.lineWidth = series.points.lineWidth;
        cx.strokeStyle = series.color;
        this._setFillStyle(series.points, series.color);
        this._plotPoints(series.data, series.points.radius, series.points.fill,series.xaxis, series.yaxis);
        cx.restore();
    },
    _drawSeriesBars: function(series) {
		this._setCanvasContext(this.ctx,{lw:series.bars.lineWidth,tl:[this.plotOffset.left, this.plotOffset.top],ss:series.color});
		var lg = series.data.length;
		if(series.bars.isColorBar){  // draw color bar
			var upD = [],downD = [];
			for(var i=0;i<lg;i++){
				if(series.data[i]!=null && series.data[i].length>3&& series.data[i][2]== 1){
					upD.push(series.data[i]);
				}else{
					downD.push(series.data[i]);
				}
			}
			this._setFillStyle(series.bars, series.bars.upColor);
        	this._plotBars(upD,0, series.bars,series.xaxis, series.yaxis,series.bars.upColor,lg);//Jacye
        	this._setFillStyle(series.bars, series.bars.downColor);
        	this._plotBars(downD,0, series.bars,series.xaxis, series.yaxis,series.bars.downColor,lg);//Jacye
		}else{
			this._setFillStyle(series.bars, series.color);
        	this._plotBars(series.data,0, series.bars,series.xaxis, series.yaxis,series.color,lg);//Jacye
		} 
        this.ctx.restore();
    },
    _drawSeriesImage: function(series) {
        this._setCanvasContext(this.ctx,{tl:[this.plotOffset.left, this.plotOffset.top],ss:series.color});
        this._plotImages(series.data, 0, series.xaxis, series.yaxis,series.imagePoints);
        this.ctx.restore();
    },
	_drawSeriesVolumeByPrice: function(series) {
        var cx = this.ctx;
		this._setCanvasContext(this.ctx,{lw:series.lines.lineWidth,tl:[this.plotOffset.left, this.plotOffset.top],fs:series.volumeByPrice.fillColor,ga:series.volumeByPrice.opacity});
        this._plotVolumeByPrice(series.data, 0, series.xaxis, series.yaxis);
        cx.restore();
    },
    _drawPointHighlight: function(series, point) {
        var ct = this.octx;
        var x = point[0], y = point[1], axisx = series.xaxis, axisy = series.yaxis;   
        if (x < axisx.min || x > axisx.max || y < axisy.min || y > axisy.max)
            return;     
        var pointRadius = series.points.radius + series.points.lineWidth / 2;
        var radius = 1.5 * pointRadius;
        ct.lineWidth = pointRadius;
        ct.strokeStyle = mstar.flotUtil.colorToRGB(series.color,0.5); 
        ct.beginPath();
        ct.arc(axisx.p2c(x), axisy.p2c(y), radius, 0, 2 * Math.PI, true);
		ct.stroke();
    },
    _drawVolumeByPriceHighlight:function(series){
		if(this.volumeByPrice.show&&this.volumeByPrice.highlights.length!=0){
			var ct = this.octx;
			ct.save();
			if(typeof(this.volumeByPrice.series.volumeByPrice)!="undefined"){
				ct.fillStyle=this.volumeByPrice.series.volumeByPrice.highlightColor;
			}
			ct.beginPath();
			var pos = this.volumeByPrice.highlights;
			ct.rect(pos[0],pos[1],pos[2],pos[3]);
			this.volumeByPrice.hintDom.css({left:(pos[0]+pos[2]+this.plotOffset.left),top:(pos[1]+this.plotOffset.top-this.volumeByPrice.hintDom.height()-pos[3])});
			var d = this.volumeByPrice.data[0][this.volumeByPrice.index];
			this.volumeByPrice.hintDom.html("Vol: "+(typeof(QS_NumFmt)=="undefined"?(d[2].toFixed(2)+" mil  Range: "+d[0].toFixed(2)+"~"+d[1].toFixed(2)):(QS_NumFmt.Fmt(d[2]*1000000,true)+"  Range: "+QS_NumFmt.Fmt2(d[0],true," ",2)+"~"+QS_NumFmt.Fmt2(d[1],true," ",2))));
			this.volumeByPrice.hintDom.show();
			ct.fill();
			ct.restore();
		}
	},
	_drawSegment:function(ct,c){
		ct.moveTo(c.spos[0],c.spos[1]);
		ct.arc(c.spos[0],c.spos[1], 1, 0, 2 * Math.PI, true);
		ct.lineTo(c.epos[0],c.epos[1]);
		ct.arc(c.epos[0],c.epos[1], 1, 0, 2 * Math.PI, true);
	},
    _drawBarHighlight: function(series, point) {
        if (point == null) {
            return; 
        }
        var ct = this.octx;
        var x = point[0],y=point[1], aw = series.bars.barWidth;          
        var cl = series.color,  op = series.bars;
		this._setCanvasContext(ct,{fs:mstar.flotUtil.colorToRGB(series.color),lw:series.bars.lineWidth,ss:mstar.flotUtil.colorToRGB(series.color)});
        if(point.length > 3) {
            cl= point[2] == 1?op.upColor:op.downColor;  
        }
        this._drawBar(x, y, aw, 0, cl, series.xaxis, series.yaxis, this.octx);
		ct.restore();
    },
    _drawOLHCHighlight: function(series,point){
        var dt = point,ct = this.octx,w = series.OLHC.barWidth;
		if(dt.length < 6 || isNaN(dt[1]) || isNaN(dt[2]) || isNaN(dt[3]) || isNaN(dt[4]))return;
		var x=dt[0], c = dt[1],h = dt[2], l=dt[3], o = dt[4];
		var px = series.xaxis.p2c(x);
		var pc = series.yaxis.p2c(c), po = series.yaxis.p2c(o), pl = series.yaxis.p2c(l), ph = series.yaxis.p2c(h);
		if(px < w/2)  px=w/2;
		if(px >(this.canvasWidth - this.plotOffset.left - this.plotOffset.right - w/2)){
		    px = this.canvasWidth - this.plotOffset.left - this.plotOffset.right - w/2;   
		}
		this._setCanvasContext(ct,{lw:series.OLHC.lineWidth+1,ss:series.OLHC.highLightColor});
		ct.beginPath();   			
		ct.moveTo(px,ph);
		ct.lineTo(px,pl);
		if(series.OLHC.olhcType=="ohlc"){
			ct.moveTo(px,po);
			ct.lineTo(px-w/2,po);
		}
		ct.moveTo(px,pc);
		ct.lineTo(px+w/2,pc);
		ct.stroke();
		ct.restore();
    },
    _drawCandleStickHighlight: function(series,point){
        var ct = this.octx; 
        var candleOption = series.candleStick;
        var maxwidth = (candleOption.maxCandleWidth == null)?16:candleOption.maxCandleWidth;
        var minwidth = (candleOption.minCandleWidth == null)?4:candleOption.minCandleWidth;
        var aw = Math.floor(0.7*(this.canvasWidth - this.plotOffset.left - this.plotOffset.right)/series.data.length);     	    
        if(aw<minwidth) aw = minwidth;
        if(aw>maxwidth) aw = maxwidth;
        var dt = point,clo;
		if(dt.length<6||isNaN(dt[1])||isNaN(dt[2])||isNaN(dt[3])||isNaN(dt[4]))return;
        this._setCanvasContext(ct,{lw:2,ss:candleOption.highLightColor,fs:candleOption.highLightColor});
        var x=dt[0], c = dt[1],h = dt[2], l = dt[3], o = dt[4];
        var px = series.xaxis.p2c(x);
        var pc = series.yaxis.p2c(c), po = series.yaxis.p2c(o), pl = series.yaxis.p2c(l), ph = series.yaxis.p2c(h);
        var ww = this.canvasWidth - this.plotOffset.right - this.plotOffset.left -aw/2;
        if(px > ww ) {
            px= ww;
        }
        if(px<aw/2) px=aw/2;
        clo = (c>o)?candleOption.upColor:candleOption.downColor;
        ct.beginPath();
        this._drawCandleStick(px,po,pl,ph,pc,dt,aw,candleOption.highLightColor,ct);
        ct.stroke();
		ct.restore();
    },
    _drawImgHighlight: function(series,point,ty){
        var ct = this.octx; 
		ct.beginPath();
		this._setCanvasContext(ct,{lw:1.5,ss:"#fff"});
		var x = this.axes.xaxis.p2c(point[0]),y = this.axes.yaxis.p2c(point[ty==0?1:3]);
		if(ty==0){y +=3;}
		ct.moveTo(x,y);
		ct.lineTo(x,this.imgDataList[point[0]]);
        ct.stroke();
		ct.restore();
    },
    _indexOfHighlight: function(s, p) {
        var h;
        for (var i = 0; i < this.highlights.length; ++i) {
            h = this.highlights[i];
            if (h.series == s && h.point[0] == p[0]&& h.point[1] == p[1]) {
                return i;
            }
        }
        return -1;
    },
	_getResultItem: function(i,j) {
        return { datapoint: this.series[i].data[j],dataIndex: j,series: this.series[i],seriesIndex: i};
    },
    _highlight:function(s, point, auto) {
        if (typeof s == "number") {
            s = this.series[s];
        }
        if (typeof point == "number") {
            point = s.data[point];
        }
        var i = this._indexOfHighlight(s, point);
        if (i == -1) {
            this.highlights.push({ series: s, point: point, auto: auto });
            this._triggerRedrawOverlay();
        } else if (!auto) {
            this.highlights[i].auto = false;
        }
		if((this.drawObj.getStart() !=""||this.volumeByPrice.show)&&i != -1){
			this._triggerRedrawOverlay();
		}
    },     
    _unhighlight:function(s, point) {
        if (typeof s == "number") {
            s = series[s];
        }
        if (typeof point == "number") {
            point = s.data[point];
        }
        var i = this._indexOfHighlight(s, point);
        if (i != -1) {
            this.highlights.splice(i, 1);
            this._triggerRedrawOverlay();
        }
    },
    _redrawOverlay: function() {
        var ct = this.octx;
        this.redrawTimeout = null;
        if(this.octx == null) return;
        ct.save();
		this._setCanvasContext(ct,{cr:[0, 0, this.canvasWidth, this.canvasHeight],tl:[this.plotOffset.left, this.plotOffset.top]});
		this.drawObj.drawGraph(ct,this.axes, this.plotOffset,this.plotWidth,this.options.yaxis.align,this.plotHeight);
        var i, hi; 
        for (i = 0; i < this.highlights.length; ++i) {
            hi = this.highlights[i],type = 1;
            if (hi.series.bars.show) {
                this._drawBarHighlight(hi.series, hi.point);
            } else if(hi.series.lines.show || hi.series.points.show) {
                this._drawPointHighlight(hi.series, hi.point);
				type = 0;
            } else if(hi.series.OLHC.show) {
                this._drawOLHCHighlight(hi.series, hi.point);
            } else if(hi.series.candleStick.show) {
                this._drawCandleStickHighlight(hi.series, hi.point);
            } else {
				type = 0;
                this._drawPointHighlight(hi.series, hi.point);
            } 
			if(this.options.imageHighlight&&this.imgDataList.length>0&&typeof(this.imgDataList[hi.point[0]])!="undefined"){
				this._drawImgHighlight(hi.series, hi.point,type);
			}   
        }
		this._drawVolumeByPriceHighlight();
        ct.restore();
    },
    _triggerRedrawOverlay: function() {
        var self = this;
        if (!this.redrawTimeout){
			clearTimeout(this.redrawTimeout);
        }
		this.redrawTimeout = setTimeout(function(){self._redrawOverlay()}, 50);
    },
    _triggerClickHoverEvent: function(eventname, event) {
		mstar.flotUtil.avoidSelect();
        if(this.eventHolder == null) {
            return false;
        }
		var off = this._getScrollOffset(event);
        var offset = this.eventHolder.offset(),
        pos = { pageX: this.lastMousePos.pageX, pageY: this.lastMousePos.pageY }, 
		canvasX = event.pageX - offset.left - this.plotOffset.left,
        canvasY = event.pageY - offset.top - this.plotOffset.top-off[1]
        if (this.axes.xaxis.used)
            pos.x = this.axes.xaxis.c2p(canvasX);
        if (this.axes.yaxis.used)
            pos.y = this.axes.yaxis.c2p(canvasY);
        if (this.axes.x2axis.used)
            pos.x2 = this.axes.x2axis.c2p(canvasX);
        if (this.axes.y2axis.used)
            pos.y2 = this.axes.y2axis.c2p(canvasY);
        var item = this._findNearbyItem(canvasX, canvasY);
        if (item) {
            // fill in mouse pos for any listeners out there
            item.pageX = parseInt(item.series.xaxis.p2c(item.datapoint[0]) + offset.left + this.plotOffset.left);
            item.pageY = parseInt(item.series.yaxis.p2c(item.datapoint[1]) + offset.top + this.plotOffset.top);  
			if(item.datapoint.length>4){
				item.maxY = parseInt(item.series.yaxis.p2c(item.datapoint[2]) + offset.top + this.plotOffset.top);
			}                  
        }
		this.drawObj.mouseMove(item,canvasX,canvasY,this.plotOffset,this.target);
		if(this.volumeByPrice.show){
            var flag = false;
            for (var i = 0; i < this.volumeByPrice.area.length; i++) {
                var tt = this.volumeByPrice.area[i];
                if (canvasX > tt[0] && canvasX < (tt[0] + tt[2]) && canvasY > tt[1] && canvasY < (tt[1] + tt[3])) {
                    this.volumeByPrice.highlights = [tt[0], tt[1], tt[2], tt[3]];
                    flag = true;
                    this.volumeByPrice.index = i;
                    break;
                }
            }
            if (this.volumeByPrice.hintDom == null) {
                this.volumeByPrice.hintDom = $("<div class='rtq-volumeByPriceHint'>dfs</div>");
                this.target.append(this.volumeByPrice.hintDom);
                this.volumeByPrice.hintDom.hide();
            }
            if (!flag) {
                this.volumeByPrice.highlights.length = 0;
                this.volumeByPrice.hintDom.hide();
            }
		}
        if (this.options.grid.autoHighlight) {
            var h;
            for (var i = 0; i < this.highlights.length; ++i) {
                h = this.highlights[i];
                if (h.auto &&!(item && h.series == item.series && h.point == item.datapoint)){
                    this._unhighlight(h.series, h.point);
                }
            }      
            if (item){
				this._highlight(item.series, item.datapoint, true);
			}else{
				this._triggerRedrawOverlay();
			}
        }  
		if(eventname=="drawEnd"){
			this.target.trigger(eventname, [event.drawType]);
		}else{
			this.target.trigger(eventname, [ pos, item ]);
		}
    },
    _findNearbyItem: function(mouseX, mouseY) {// Returns the data item the mouse is over, or null if none is found
        var maxDistance = this.options.grid.mouseActiveRadius;
        var lowestDistance = maxDistance * maxDistance + 1;
        var item = null, foundPoint = false;
        var data, axisx, axisy, mx, my, maxx, maxy, checkbar, checkcandle, checkOLHC, checkpoint, barLeft, barRight, candlew;
        var s = this.series[0], i = 0;
        if(s&&this.options.higlightIndex < s.length) {
            s = this.series[this.options.higlightIndex];
            i = this.options.higlightIndex;
        }
		if(!s||!s.xaxis||!s.yaxis)return null;
        data = s.data, axisx = s.xaxis, axisy = s.yaxis;
        mx = axisx.c2p(mouseX), my = axisy.c2p(mouseY);
        maxx = maxDistance / axisx.scale, maxy = maxDistance / axisy.scale;
        checkbar = s.bars.show , checkcandle = s.candleStick.show, checkOLHC = s.OLHC.show;
        checkpoint = (!checkOLHC && !checkcandle && !checkbar)||(s.lines.show || s.points.show);
        if (s.bars.show&&typeof(s[i])!="undefined") barLeft = s[i].bars.align == "left" ? 0 : - s.bars.barWidth/2, barRight = barLeft + s.bars.barWidth;
        if (s.candleStick.show) candlew = s.candleStick.candleWidth == null ? 0:s.candleStick.candleWidth;
        var x, y, lg = data.length;
        for (var j = 0; j < lg; ++j) {
            if (data[j] == null||isNaN(data[j][1])||(data[j].length>6&&data[j][6]==1))// fill point.
                continue;
            x = data[j][0], y = data[j][1];
            if (s.bars.show) {
                // For a bar graph, the cursor must be inside the bar
                // and no other point can be nearby
                if (!foundPoint && mx >= x + barLeft && mx <= x + barRight && my >= Math.min(0, y) && my <= Math.max(0, y)) {
                    item = this._getResultItem(i, j);
                    item.y = my;
                }
            } else if(s.candleStick.show || s.OLHC.show) {
                if ((mx <= x+0.5)) { //&&(mx >= x-0.5)
                  foundPoint = true;
                  item = this._getResultItem(i, j);
                  item.y = my;
                  return  item;
                }
            } else {
                 if ((mx <= x+0.5)) {
                   foundPoint = true;
                   item = this._getResultItem(i, j);
                   item.y = my;
                   return  item;
                } 
            }
        }
        return item;
    },
	_getScrollOffset:function(ev){
		var de = document.documentElement, b = document.body;
		var sl= de && de.scrollLeft || b.scrollLeft || 0, sr = de && de.scrollTop || b.scrollTop || 0;
		return [sl,sr];
	},
    _onMouseMove: function(ev) {
        // FIXME: temp. work-around until jQuery bug 1871 is fixed
		mstar.flotUtil.avoidSelect();
        var self = this;
		var e = ev || window.event;
        var off = this._getScrollOffset(ev);
		sl = off[0],sr=off[1];
        if (e.pageX == null && e.pageX != null) { // IE
            this.lastMousePos.pageX = e.pageX + sl;
            this.lastMousePos.pageY = e.pageY + sr;
        }
        else {
            this.lastMousePos.pageX = e.pageX+sl;
            this.lastMousePos.pageY = e.pageY+sr;
        }
        
        if (this.options.grid.hoverable && !this.hoverTimeout)
            this.hoverTimeout = setTimeout(function(){self._onHover()}, 100);
    },
	_getItem:function(e){
		var offset = this.eventHolder.offset();
		var xy = this._getCanvasXY(e);
		var canvasX=xy[0],canvasY=xy[1];
		var item = this._findNearbyItem(canvasX, canvasY);
        if (item) {
            item.pageX = parseInt(item.series.xaxis.p2c(item.datapoint[0]) + offset.left + this.plotOffset.left);
            item.pageY = parseInt(item.series.yaxis.p2c(item.datapoint[1]) + offset.top + this.plotOffset.top);                  
        }
		return item;
	},
    _onMouseDown: function(e) {
		mstar.flotUtil.avoidSelect();
        var self = this;
        if (e.which != 1&&(typeof(__isMobile)=="undefined"||__isMobile===false))  // only accept left-click
            return;
        document.body.focus();
        this.lastMousePos.pageX = null;
		var xy = this._getCanvasXY(e);
		var canvasX=xy[0],canvasY=xy[1];
		var item = this._getItem(e);
		
		this.drawObj.mouseDown(e,xy,item,this.axes,this.target,this.plotOffset,this.series);
		this._triggerRedrawOverlay();
		if(typeof(__isMobile)!="undefined"&&__isMobile===true){
			$(document).bind("mouseup.msflot", function(e){
				self._onMouseUp.call(self,e);
				$(document).unbind("mouseup.msflot");
			});
		}else{
			$(document).one("mouseup", function(e){self._onMouseUp.call(self,e);});
		}
    },
	_getCanvasXY:function(e){
		var offset = this.eventHolder.offset();
		var xx,yy;
		var de = document.documentElement, b = document.body;
		var sl= de && de.scrollLeft || b.scrollLeft || 0, sr = de && de.scrollTop || b.scrollTop || 0;
        if (e.pageX == null && e.pageX != null) { // IE
           xx = e.pageX + sl;
            yy= e.pageY + sr;
        }
        else {
            xx = e.pageX+sl;
            yy = e.pageY+sr;
        }
        canvasX =e.pageX - offset.left - this.plotOffset.left,
        canvasY = e.pageY - offset.top - this.plotOffset.top;
		return [canvasX,canvasY];
	},
    _onClick:function(e) { 
		var offset = this.eventHolder.offset();
		if(e.pageX<(this.eventHolder.offset().left+this.plotOffset.left)){
			return ;
		}
        this._triggerClickHoverEvent("plotclick", e);
    },  
	_ondbClick:function(e){
		var xy=this._getCanvasXY(e);
		var item = this._getItem(e);
		this.drawObj.dbClick(e,xy,item);
		this._triggerRedrawOverlay();
	} , 
    _onHover:function() {
        this._triggerClickHoverEvent("plothover", this.lastMousePos);
        this.hoverTimeout = null;
    },
    _onMouseUp: function(e) {
		var offset = this.eventHolder.offset();
		var xy = this._getCanvasXY(e);
		var item = this._findNearbyItem(xy[0], xy[1]);
		fl = this.drawObj.mouseUp(e,xy,item,offset,this.plotOffset,this.plotHeight,this.axes,this.target);
		e.drawType = fl[0];
		e.moving = fl[1];
		e.draging = fl[2]
		this.target.css("cursor","");
		this._triggerRedrawOverlay();
		if(e.drawType&&!e.moving&&!e.draging){  // draw end.
			this._triggerClickHoverEvent("drawEnd",e); 
		}
        return false;
    },
	_insertLastDataPointAxisLabel:function(series){//add by yuntao to insert the last data point label
		var color=series.color,
			len=series.data.length,
			html="",top,lastVal,
			oset = this.plotOffset,
			axis=series.yaxis;
		for(var i=len-1;i>=0;i--){
			lastVal=series.data[i][1];
			if(!isNaN(lastVal)){
				break;
			}
		}
		if (!series.showLegend&&axis.showLastLabel) {
			top = oset.top + axis.p2c(lastVal)-axis.labelHeight;
			if(top<0){ 
				top=0;
			}
			if(typeof axis.labelFormatter=='function'){
				lastVal=axis.labelFormatter(lastVal);
			}
			var cls = color.replace(/[)]/g,"").replace(/[(,]/g,"-").replace(/[#]/,"c-");
			html = '<div class="tickLabel '+cls+'" style="background:' + color + ';color:#000;position:absolute;top:' + top + 'px;right:' + (oset.right + ((this.options.yaxis.align != "right") ? this.plotWidth : 0) + this.options.grid.labelMargin) + 'px;text-align:right">' + lastVal + "</div>";
			this.target.find(".tickLabels")[0].innerHTML += html;
		}
	},
    _drawSeries: function(series) {
		var flag=false;
        if (series.lines.show || (!series.bars.show && !series.points.show && !series.OLHC.show && !series.candleStick.show && !series.imagePoints.show && !series.volumeByPrice.show)) {
			flag = true;
			this._drawSeriesLines(series);
		}if (series.bars.show){
			flag=true;
			this._drawSeriesBars(series);			
		}
		if (series.points.show){
		 	flag=true;
			this._drawSeriesPoints(series);
		}
        if(series.OLHC.show){
            flag=true;
			this._drawSeriesOLHC(series);
        }
        if(series.candleStick.show){ 
            flag=true;
			this._drawSeriesCandleStick(series);
        }
        if(series.imagePoints.show){
            flag=false;
			this._drawSeriesImage(series);
        }
		if(series.volumeByPrice.show){
			flag=true;
			this.volumeByPrice.show =true;
			this.volumeByPrice.series = series;
            this._drawSeriesVolumeByPrice(series);
        }
		if (flag) {
			this._insertLastDataPointAxisLabel(series);
		}
    },
    _constructChart: function() {
		this._drawGrid();
		this._insertAxisLabels();
		this.volumeByPrice.show =false;
        for (var i = 0; i < this.series.length; i++) {
            this._drawSeries(this.series[i]);
        }
    },
	setChartTypeForDrawings: function(type,startPos){
		if(this.drawObj){
			this.drawObj.chartType = type;
			this.drawObj.startPos=startPos
		}
	},
    _clearCanvas: function(){
		if(this.ctx&&this.octx){
			this.ctx.clearRect(0, 0, this.canvasWidth, this.canvasHeight);
	        this.octx.clearRect(0, 0, this.canvasWidth, this.canvasHeight);
	        if ($.browser.msie) { 
	            this.ctx.canvas.onPropertyChange = null;
	            this.ctx.canvas.onResize = null;
	            this.octx.canvas.onPropertyChange = null;
	            this.octx.canvas.onResize = null;
	            this.ctx.element_ = null; this.ctx.canvas = null;
	            this.ctx.currentPath_ = null; this.ctx.m_ = null      
	            this.octx.element_ = null; this.octx.canvas = null;
	            this.octx.currentPath_ = null;this.octx.m_ = null     
	        }
	        this.target.unbind("plothover");
	        this.eventHolder.each(function () {
	             $(this).unbind("mousemove");
	             $(this).unbind("mousedown");
	             $(this).unbind("click");
	        }); 
        	this.ctx = this.octx = this.canvas  = this.overlay = this.eventHolder = null;
		}
      	this.target.find(".flot-minichart").remove();
        this.target.find("canvas,.tickLabels").remove();
    },
    clear: function() { 
        this._clearCanvas();
        this.target = this.series = this.options =  this.axes = null;;   
        for(var p in this){
            if(!p || p == 'clear'){continue;}
            this[p] = null;
            delete this[p];
        }
    }
}